package demo.mq.rocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import demo.java.net.HttpDemo;
import demo.mq.rocket.vo.ConsoleResponse;
import demo.mq.rocket.vo.GroupInfo;
import demo.mq.rocket.vo.GroupStatInfo;
import demo.mq.rocket.vo.QueueStatInfo;
import demo.mq.rocket.vo.TopicQueueStats;
import demo.vo.exp.ServiceException;
import demo.vo.http.ResponseVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMethod;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * RocketMQ console API
 * 
 * @author junying.han
 *
 */
public class RocketMqConsoleApi {

    private static Logger logger = LoggerFactory.getLogger(RocketMqConsoleApi.class);

    private String url;
    private String user;
    private String pass;

    /** 请求接口加密 */
    private Map<String, String> headers;

    public RocketMqConsoleApi(String url, String user, String pass) {
        super();
        this.url = url;
        this.user = user;
        this.pass = pass;
        this.headers = new HashMap<String, String>();
    }

    /**
     * 查询组对应的TOPIC 信息
     * 
     * @param consumerGroup
     * @return
     * @throws ServiceException
     * @throws IOException
     */
    public List<GroupStatInfo> queryTopicByConsumer(String consumerGroup) throws ServiceException, IOException {
        String path = url + "/consumer/queryTopicByConsumer.query?consumerGroup=" + consumerGroup;
        ResponseVo response = HttpDemo.httpRequest(path, null, RequestMethod.GET, headers, 6000, 60_000);
        if (!response.getHttpStatus().is2xxSuccessful()) {
            throw new ServiceException(response.toString());
        }
        ConsoleResponse<List<GroupStatInfo>> consoleResponse = JSON.parseObject(response.getContent(),
                new TypeReference<ConsoleResponse<List<GroupStatInfo>>>() {
                });
        if (consoleResponse.getStatus() != null && consoleResponse.getStatus().intValue() != 0) {
            throw new ServiceException(consoleResponse.getErrMsg());
        }
        return consoleResponse.getData();
    }

    /**
     * 查询TOPIC 消费者信息
     * 
     * @param topic
     * @throws IOException
     * @throws ServiceException
     */
    public List<GroupInfo> groupList() throws IOException, ServiceException {
        String path = url + "/consumer/groupList.query";
        ResponseVo response = HttpDemo.httpRequest(path, null, RequestMethod.GET, headers, 6000, 60_000);
        if (!response.getHttpStatus().is2xxSuccessful()) {
            throw new ServiceException(response.toString());
        }
        ConsoleResponse<List<GroupInfo>> consoleResponse = JSON.parseObject(response.getContent(),
                new TypeReference<ConsoleResponse<List<GroupInfo>>>() {
                });
        if (consoleResponse.getStatus() != null && consoleResponse.getStatus().intValue() != 0) {
            throw new ServiceException(consoleResponse.getErrMsg());
        }
        return consoleResponse.getData();
    }

    /**
     * 查询TOPIC 消费者信息
     * 
     * @param topic
     * @throws IOException
     * @throws ServiceException
     */
    public JSONObject queryConsumerByTopic(String topic) throws IOException, ServiceException {
        String path = url + "/topic/queryConsumerByTopic.query?topic=" + topic;
        ResponseVo response = HttpDemo.httpRequest(path, null, RequestMethod.GET, headers, 6000, 60_000);
        if (!response.getHttpStatus().is2xxSuccessful()) {
            throw new ServiceException(response.toString());
        }
        ConsoleResponse<JSONObject> consoleResponse = JSON.parseObject(response.getContent(),
                new TypeReference<ConsoleResponse<JSONObject>>() {
                });
        if (consoleResponse.getStatus() != null && consoleResponse.getStatus().intValue() != 0) {
            throw new ServiceException(consoleResponse.getErrMsg());
        }
        return consoleResponse.getData();
    }

    /**
     * 查询TOPIC 消费者信息
     * 
     * @param topic
     * @throws IOException
     * @throws ServiceException
     */
    public List<GroupStatInfo> queryConsumerByTopicAsList(String topic) throws IOException, ServiceException {
        JSONObject json = queryConsumerByTopic(topic);
        if (json == null || json.isEmpty()) {
            return Collections.emptyList();
        }
        List<GroupStatInfo> list = new ArrayList<GroupStatInfo>(json.size());
        for (Entry<String, Object> entry : json.entrySet()) {
            GroupStatInfo vo = new GroupStatInfo();
            vo.setGroup(entry.getKey());
            JSONObject value = (JSONObject) entry.getValue();
            vo.setDiffTotal(value.getInteger("diffTotal"));

            vo.setLastTimestamp(value.getLong("lastTimestamp"));
            vo.setQueueStatInfoList(value.getObject("queueStatInfoList", new TypeReference<List<QueueStatInfo>>() {
            }));
            vo.setTopic(value.getString("topic"));
            list.add(vo);
        }
        return list;
    }

    /**
     * topic 统计信息
     * 
     * @param topic
     * @return
     * @throws IOException
     * @throws ServiceException
     */
    public List<TopicQueueStats> topicStatsAsList(String topic) throws IOException, ServiceException {
        JSONObject json = topicStats(topic);
        if (json == null || json.isEmpty()) {
            return Collections.emptyList();
        }
        List<TopicQueueStats> list = new ArrayList<TopicQueueStats>(json.size());
        for (Entry<String, Object> entry : json.entrySet()) {
            TopicQueueStats vo = new TopicQueueStats();
            vo.setQueue(entry.getKey());
            JSONObject value = (JSONObject) entry.getValue();
            vo.setLastUpdateTimestamp(value.getLong("lastUpdateTimestamp"));
            vo.setMaxOffset(value.getInteger("maxOffset"));
            vo.setMinOffset(value.getInteger("minOffset"));
            list.add(vo);
        }
        return list;
    }

    /**
     * topic 统计信息
     * 
     * @param topic
     * @return
     * @throws IOException
     * @throws ServiceException
     */
    public JSONObject topicStats(String topic) throws IOException, ServiceException {
        String path = url + "/topic/stats.query?topic=" + topic;
        ResponseVo response = HttpDemo.httpRequest(path, null, RequestMethod.GET, headers, 6000, 60_000);
        if (!response.getHttpStatus().is2xxSuccessful()) {
            throw new ServiceException(response.toString());
        }
        ConsoleResponse<JSONObject> consoleResponse = JSON.parseObject(response.getContent(),
                new TypeReference<ConsoleResponse<JSONObject>>() {
                });
        if (consoleResponse.getStatus() != null && consoleResponse.getStatus().intValue() != 0) {
            throw new ServiceException(consoleResponse.getErrMsg());
        }
        JSONObject json = consoleResponse.getData();
        if (json == null || json.isEmpty()) {
            return null;
        }
        return json.getJSONObject("offsetTable");
    }

    /**
     * <p>
     * 
     * @throws IOException
     * @throws ServiceException
     */
    public Map<String, List<String>> topicListGroupByType() throws IOException, ServiceException {
        List<String> list = topicList();
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        List<String> normal = new ArrayList<String>();
        List<String> retry = new ArrayList<String>();
        List<String> dlq = new ArrayList<String>();
        List<String> system = new ArrayList<String>();
        map.put("normal", normal);
        map.put("retry", retry);
        map.put("dlq", dlq);
        map.put("system", system);
        for (String string : list) {
            if (string.startsWith("%RETRY%")) {
                retry.add(string);
            } else if (string.startsWith("%DLQ%")) {
                dlq.add(string);
            } else if (string.startsWith("%SYS%")) {
                system.add(string);
            } else {
                normal.add(string);
            }
        }
        return map;
    }

    /**
     * <p>
     * 
     * @throws IOException
     * @throws ServiceException
     */
    public List<String> topicList() throws IOException, ServiceException {
        String path = url + "/topic/list.query";
        ResponseVo response = HttpDemo.httpRequest(path, null, RequestMethod.GET, headers, 6000, 60_000);
        if (!response.getHttpStatus().is2xxSuccessful()) {
            throw new ServiceException(response.toString());
        }
        ConsoleResponse<JSONObject> consoleResponse = JSON.parseObject(response.getContent(),
                new TypeReference<ConsoleResponse<JSONObject>>() {
                });
        if (consoleResponse.getStatus() != null && consoleResponse.getStatus().intValue() != 0) {
            throw new ServiceException(consoleResponse.getErrMsg());
        }
        JSONObject json = consoleResponse.getData();
        if (json == null || json.isEmpty()) {
            return Collections.emptyList();
        }
        JSONArray topicList = json.getJSONArray("topicList");
        if (topicList == null || topicList.isEmpty()) {
            return Collections.emptyList();
        }
        return topicList.toJavaList(String.class);
    }

    /**
     * <p>
     * 
     * @throws IOException
     * @throws ServiceException
     */
    public List<String> topicCurrent() throws IOException, ServiceException {
        String path = url + "/dashboard/topicCurrent?_=" + System.currentTimeMillis();
        ResponseVo response = HttpDemo.httpRequest(path, null, RequestMethod.GET, headers, 6000, 60_000);
        if (!response.getHttpStatus().is2xxSuccessful()) {
            throw new ServiceException(response.toString());
        }
        ConsoleResponse<List<String>> data = JSON.parseObject(response.getContent(),
                new TypeReference<ConsoleResponse<List<String>>>() {
                });
        if (data.getStatus() != null && data.getStatus().intValue() == 0) {
            return data.getData();
        } else {
            throw new ServiceException(data.getErrMsg());
        }
    }

    /**
     * 登陆
     * 
     * @param userName
     * @param password
     * @return
     * 
     *         <pre>
     * {
        "status": 0,
        "data": {
            "user": {
                "id": 0,
                "name": "admin",
                "password": null,
                "type": 1
            },
            "loginTime": 1603094940358,
            "ip": "192.168.121.149",
            "sessionId": "57D8E3F3FE870009C6ECED4AB9439EA6"
        },
        "errMsg": null
    }
     *         </pre>
     * 
     * @throws IOException
     * @throws ServiceException
     */
    public JSONObject loggin() throws IOException, ServiceException {
        String path = url + String.format("/login/login.do?username=%s&password=%s", user, pass);
        ResponseVo response = HttpDemo.httpRequest(path, null, RequestMethod.POST, headers, 6000, 60_000);
        if (!response.getHttpStatus().is2xxSuccessful()) {
            throw new ServiceException(response.toString());
        }
        String data = response.getContent();
        ConsoleResponse<JSONObject> dataJson = JSON.parseObject(data, new TypeReference<ConsoleResponse<JSONObject>>() {
        });
        if (dataJson.getStatus() != null && dataJson.getStatus().intValue() == 0) {
            return dataJson.getData();
        } else {
            throw new ServiceException(dataJson.getErrMsg());
        }
    }

    /**
     * 登陆
     * 
     * @return
     * 
     * @throws IOException
     * @throws ServiceException
     */
    public String logginGetSessionId() throws IOException, ServiceException {
        JSONObject data = loggin();
        String sessionId = data.getString("sessionId");
        headers.put("Cookie", String.format("JSESSIONID=%s", sessionId));
        return sessionId;
    }

    public String getUrl() {
        return url;
    }

    public String getUser() {
        return user;
    }

    public String getPass() {
        return pass;
    }

}
